package com.lcy.lambda.function.柯里化;

/**
 * @author lcy
 * @date 2025/11/5 16:44
 */
public class 柯里化1 {
    @FunctionalInterface
    interface F2{
        int op(int a, int b);
    }

    public static void main(String[] args) {
        //如果我一开始就能拿到a和b
        F2 f2 = (a, b) -> a + b;
        System.out.println(f2.op(1, 2));

        //改造下需求,如果我没法在同一时刻获取a 和 b,每一个步骤只能拿到一个参数。
        //那么可以进行一下改造，第一步只能拿到参数a,计算规则已知是a + b,但是参数b需要第二个函数才能计算出来。
        //

        /* 改造
           已知我最终计算规则是 a + b  但是第一步只能拿到a参数,
                此时我拥有的东西有两个：
                    1. 参数a
                    2. 计算规则a + b
                此时我缺少的只是参数b


         * 第一步 (a) -> 返回第二个函数对象    第一步中原本拿不到参数b,因此先定义一个函数方法,告诉第二步拿到b以后该怎么做
         * 第二步 可以得到b了,
                (b) -> a + b    //其中a是闭包参数   第二个函数可以帮第一个函数收集到参数b
         */

        //================对于Fb接口的用法=====================

        //用法1,b参数自己玩自己的
//        Fb fb1 = b -> b*b;
//        System.out.println(fb1.op(2));
//
//        //用法2,结合闭包,和已知的参数进行运算
//        int c = 3; //已知的东西
//        Fb fb2 = b -> b * c;
//        System.out.println(fb2.op(2)); //此时只需要传一个参数2,就可以进行两个参数的计算了 2 * 3

        //================对于Fa接口的用法=====================
        Fa fa = new Fa() {
              /* 已知我最终计算规则是 a + b  但是第一步只能拿到a参数,
                此时我拥有的东西有两个：
                    1. 参数a
                    2. 计算规则a + b
                此时我缺少的只是参数b
               */
            @Override
            public Fb op(int a) {
                //我拿到了a,但是没法立刻进行a+b的计算,只能等待今后拿到b后才进行计算。
                Fb fb = new Fb() {
                    @Override
                    public int op(int b) {
                        //此时拿到b,并且拿到a,进行计算
                        return a + b;
                    }
                };
                return fb;
            }
        };
        //上一步执行后，此时生成了Fa的代理类：柯里化1$1，一个Fa的对象fa,这个对象没有任何属性，只有一个方法op，在java堆中，占用内存的大小只有最基本的对象头，
        //方法Fb op(int a); 在方法区，不执行的时候是不会在堆栈中创建变量的。


        //这一步中，由于真正执行了op方法，因此在堆栈中给fa对象的a参数赋值3,并且生成了一个Fb的代理类：柯里化1$1$1，一个Fb的对象fb,
        // 这个对象fb占用的内存大小是基本的对象头和参数a（闭包带过来的）的大小
        Fb fb = fa.op(3);

        //执行fb的方法op后，会去方法区找到op方法，生成该生成的局部变量。 此时局部变量有参数b。  注意参数a是fb的final类型的成员变量，不是局部变量
        //此时真正的生成此时
        int result = fb.op(4);
        System.out.println(result);

        //总结：柯里化的思想就是，提前知道最终的规则，但是无法立刻拿到参数，等待参数一步步的传入
        //最开始的函数接受到的参数会变成后续接口函数的匿名内部类的闭包参数（本质上是成员变量）
        //直到最后的函数接口的实例对象调用最后的一个方法后，规则才最终执行。
    }
    @FunctionalInterface
    interface Fa{
        Fb op(int a);
    }
    @FunctionalInterface
    interface Fb{
        int op(int b);
    }
}
